package com.xy.controller.auth;

import com.aliyuncs.exceptions.ClientException;
import com.xy.common.base.ApiBaseResponse;
import com.xy.entity.User;
import com.xy.service.AuthService;
import com.xy.util.SendSmsUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.AuthenticationException;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.xml.crypto.Data;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Created by Thinkpad on 2018/1/7.
 */
@Api(value = "用户controller", description = "用户操作")
@RestController
@RequestMapping(value = "/auth")
public class AuthController {

    @Autowired
    private AuthService authService;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    public static final String REGISTER_SMS_REDIS_PREFIX = "REGISTER";
    public static final String RAPID_LOGIN_SMS_REDIS_PREFIX = "RAPID_LOGIN";

    @ApiOperation(value = "登录", notes = "返回currentToken之后requestHead中放入{'Authorization':'Bearer'+返回的currentToken}")
    @PostMapping(value = "/login")
    @ResponseStatus(HttpStatus.OK)
    public ResponseEntity<?> login(@RequestBody User user) {
        try {
            User resultUser = authService.login(user.getUsername(), user.getPassword());
            return ResponseEntity.ok(ApiBaseResponse.fromHttpStatus(HttpStatus.OK, resultUser));
        } catch (Exception e) {
            if (e.getMessage().equals("Bad credentials")) {
                return ResponseEntity.ok(ApiBaseResponse.fromHttpStatus(HttpStatus.BAD_REQUEST, "用户名或密码错误！"));
            }

            return ResponseEntity.ok(ApiBaseResponse.fromHttpStatus(HttpStatus.BAD_REQUEST, e.getMessage()));
        }
    }


    @ApiOperation("快速登录")
    @PostMapping(value = "/rapid")
    @ResponseStatus(HttpStatus.OK)
    public ResponseEntity<?> createSmsToken(@RequestBody User user) throws AuthenticationException {

        try {
            String cachCode = stringRedisTemplate.opsForValue().get(RAPID_LOGIN_SMS_REDIS_PREFIX + user.getUsername());
            if (!cachCode.split("_")[0].equals(user.getCode())) {
                return ResponseEntity.ok(ApiBaseResponse.fromHttpStatus(HttpStatus.BAD_REQUEST, "验证码错误"));
            }

            User resultUser = authService.login(user.getUsername());
            return ResponseEntity.ok(ApiBaseResponse.fromHttpStatus(HttpStatus.OK, resultUser));
        } catch (Exception e) {
            return ResponseEntity.ok(ApiBaseResponse.fromHttpStatus(HttpStatus.BAD_REQUEST, e.getMessage()));
        }

    }


    @ApiOperation("注册")
    @PostMapping(value = "/register")
    public ResponseEntity<?> register(@RequestBody User addUser) throws AuthenticationException {
        String cachCode = stringRedisTemplate.opsForValue().get(REGISTER_SMS_REDIS_PREFIX + addUser.getUsername());
        if (!cachCode.split("_")[0].equals(addUser.getCode())) {
            return ResponseEntity.ok(ApiBaseResponse.fromHttpStatus(HttpStatus.BAD_REQUEST, "验证码错误"));
        }

        if (new Date().getTime() - Long.parseLong(cachCode.split("_")[1]) > 600000) {
            return ResponseEntity.ok(ApiBaseResponse.fromHttpStatus(HttpStatus.BAD_REQUEST, "验证码失效"));
        }

        User user = authService.register(addUser);
        return ResponseEntity.ok(ApiBaseResponse.fromHttpStatus(HttpStatus.OK, user.getUuid()));
    }

    @ApiOperation(value = "发送短信验证码", notes = "注册:'REGISTER',快速登录:'RAPID_LOGIN'")
    @GetMapping(value = "/sendCode/{phone}/{sendType}")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "phone", value = "手机号", required = true),
            @ApiImplicitParam(name = "sendType", value = "短信类型", required = true, example = "注册时填'REGISTER'")
    })
    public ResponseEntity<?> sendCode(@PathVariable("phone") String phone, @PathVariable("sendType") String sendType, HttpServletRequest request) throws ClientException {

        String visitor = request.getRemoteAddr();
        System.out.println("来访者ip" + visitor);

        String temp = stringRedisTemplate.opsForValue().get(visitor);
        int tempInt = 0;
        if (!StringUtils.isEmpty(temp) && Integer.parseInt(temp) > 0) {
            tempInt = Integer.parseInt(temp);
        }

        if (tempInt > 100) {
            return ResponseEntity.ok(ApiBaseResponse.fromHttpStatus(HttpStatus.BAD_REQUEST, "请求超过100次"));
        } else {
            tempInt += 1;
            stringRedisTemplate.opsForValue().set(visitor, tempInt + "");
        }

        String cachCode = stringRedisTemplate.opsForValue().get(sendType + phone);
        if (!StringUtils.isEmpty(cachCode)) {
            if (new Date().getTime() - Long.parseLong(cachCode.split("_")[1]) < 60000) {
                return ResponseEntity.ok(ApiBaseResponse.fromHttpStatus(HttpStatus.BAD_REQUEST, "距上次发送短信间隔不足1分钟"));
            }
        }

        String code = SendSmsUtil.SendSms(phone, sendType);
        stringRedisTemplate.opsForValue().set(sendType + phone, code + "_" + new Date().getTime());

        System.out.println("短信验证码：" + code);

        if (!code.equals("200")) {
            return ResponseEntity.ok(ApiBaseResponse.fromHttpStatus(HttpStatus.OK, code));
        }
        return ResponseEntity.ok(ApiBaseResponse.fromHttpStatus(HttpStatus.OK));
    }

    @ApiOperation("校验手机号")
    @GetMapping(value = "/checkPhone/{phone}")
    @ApiImplicitParams(
            @ApiImplicitParam(name = "phone", value = "手机号", required = true)
    )
    public ResponseEntity<?> checkPhone(@PathVariable("phone") String phone) throws ClientException {
        return ResponseEntity.ok(ApiBaseResponse.fromHttpStatus(HttpStatus.OK, matchPhone(phone)));
    }


    private boolean matchPhone(String phone) {
        String regex = "^((13[0-9])|(14[5|7])|(15([0-3]|[5-9]))|(17[013678])|(18[0,5-9]))\\d{8}$";
        if (StringUtils.isEmpty(phone) || phone.length() != 11) {
            return false;
        } else {
            Pattern p = Pattern.compile(regex);
            Matcher m = p.matcher(phone);
            boolean isMatch = m.matches();
            return isMatch;
        }
    }

}
